﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class SlgEntitySoldier : BattleEntity
{
    public GameObject m_pGameObj;
    public GameObject m_pRender;
    public SoldierVo m_pVo;
    public SlgBattleMgr.SoldierRenderType m_RenderType;
    //带时间缩放的动画控制器
    public AnimationComp m_pAnimation;
    public SkeletonAnimation m_pSkele;
    public NStateMachine<SlgEntitySoldier> m_pStateMachine;
    public MoveComp m_pMoveComp;
    private Transform m_pShadow;

    public PhysObject m_PhysObject;
    public bool m_bDead = false;
    public bool InLoop
    {
        get
        {
            if (m_RenderType == SlgBattleMgr.SoldierRenderType.Model && m_pAnimation != null)
            {
                return m_pAnimation.IsLoop;
            }
            if (m_RenderType == SlgBattleMgr.SoldierRenderType.Spine && m_pSkele != null)
            {
                return m_pSkele.loop;
            }
            return false;
        }
    }

    public int TroopIndex
    {
        set
        {
            m_pGameObj.name = "Entity_Soldier_" + m_pVo.pos + "_" + value.ToString();
            m_iTroopIndex = value;
        }
        get { return m_iTroopIndex; }
    }
    private int m_iTroopIndex = 0;
    private string m_sActionName;


    public double LastSearchTime = 0;
    public double LastFreshDirTime = 0;
    public double LastAttackTime = 0;
    public double LastMoveTime = 0;
    public bool m_bInAttack = false;
    public string m_strActionName = "";

    public override void OnCreate(params object[] args)
    {
        m_pVo = (SoldierVo)args[0];
        m_RenderType = (SlgBattleMgr.SoldierRenderType)args[1];
        Vector3 pos = (Vector3)args[2];
        float scale = (float)args[3];
        if (m_RenderType == SlgBattleMgr.SoldierRenderType.Model)
        {
            m_pRender = GameObject.Instantiate<GameObject>(SlgBattleMgr.Instance.m_DicModel[m_pVo.config.model + "_3D"]);
            Animation ani = m_pRender.GetComponentInChildren<Animation>();
            m_pAnimation = new AnimationComp(ani, AnimationEnd);
            m_pShadow = m_pRender.transform.Find("ProShadow");
        }
        else if(m_RenderType == SlgBattleMgr.SoldierRenderType.Spine)
        {
            m_pRender = GameObject.Instantiate<GameObject>(SlgBattleMgr.Instance.m_DicSpines[m_pVo.config.model + "_Spine"]);
            m_pSkele = m_pRender.GetComponent<SkeletonAnimation>();
            m_pSkele.state.Complete += HandleSpine_Comp;
        }
        m_pGameObj = new GameObject();
        m_pGameObj.name = "Entity_Soldier_" + m_pVo.pos;
        m_pGameObj.transform.position = pos;
        m_pGameObj.transform.localScale = Vector3.one;
        m_pGameObj.transform.localEulerAngles = GetForwards();
        m_pRender.transform.SetParent(m_pGameObj.transform);
        m_pRender.transform.localPosition = Vector3.zero;
        m_pRender.transform.localScale = GetScale(scale); 
        m_pRender.transform.localEulerAngles = new Vector3(0, 0, 0);
        //m_pRender.gameObject.layer = m_pVo.m_bleft ? SlgFightDef.c_iLay_LeftTroop : SlgFightDef.c_iLay_RightTroop; 

        //状态机
        Dictionary<string, NState<SlgEntitySoldier>> states = new Dictionary<string, NState<SlgEntitySoldier>>()
        {
            {SlgSoldierState.c_sSoldier_Idle,SlgSoldierState.s_pSoldier_Idle },
            //{SlgSoldierState.c_sSoldier_Global,SlgSoldierState.s_pSoldier_Global },
            {SlgSoldierState.c_sSoldier_Move,SlgSoldierState.s_pSoldier_Move },
            //{SlgSoldierState.c_sSoldier_Attack,SlgSoldierState.s_pSoldier_Attack }
            {SlgSoldierState.c_sSoldier_Dead,SlgSoldierState.s_pSoldier_Dead },
            {SlgSoldierState.c_sSolider_Action,SlgSoldierState.s_pSolider_Action },
            {SlgSoldierState.c_sSolider_Shoot,SlgSoldierState.s_pSolider_Shoot }
        };
        m_pStateMachine = new NStateMachine<SlgEntitySoldier>(this, states, SlgSoldierState.c_sSoldier_Global);
        m_pStateMachine.ChangeState(SlgSoldierState.c_sSoldier_Idle);

        m_pMoveComp = new MoveComp(m_pGameObj.transform, this);
        //m_PhysObject = new PhysObject();
    }

    public override void OnUpdate(float deltaTime)
    {
        base.OnUpdate(deltaTime);
        m_pStateMachine.OnUpdate();
        m_pMoveComp.OnUpdate(deltaTime);
        if (m_pAnimation != null)
        {
            m_pAnimation.OnUpdate(deltaTime);
        }
        else if(m_pSkele != null)
        {
            m_pSkele.timeScale = SlgBattleMgr.Instance.Speed;
        }
    }

    public override void OnDestroy()
    {
        GameObject.Destroy(m_pGameObj);
    }

    public void AnimationEnd(string clipName,int num)
    {
        EntityMessageDispatcher.Instance.SendMessage(m_sActionName, Id, Id);
    }
    private void HandleSpine_Comp(Spine.AnimationState state, int trackIndex, int loopCount)
    {
        // clipName = state.GetCurrent(trackIndex).Animation.Name
        EntityMessageDispatcher.Instance.SendMessage(m_sActionName, Id, Id);
    }

    public void PlayAction(string action, bool isLoop = false)
    {
        m_sActionName = action;
        //这边要转换下  spine和3d的动画 名字不一样
        action = Action2ClipName(action);
        if (string.IsNullOrEmpty(action))
            return;

        if(m_RenderType == SlgBattleMgr.SoldierRenderType.Model && m_pAnimation != null)
        {
            action = m_pVo.config.prefabName + "@" + action;
            m_pAnimation.Play(action, isLoop);
        }

        if(m_RenderType == SlgBattleMgr.SoldierRenderType.Spine && m_pSkele != null)
        {
            m_pSkele.loop = isLoop;
            m_pSkele.AnimationName = action;
        }
    }
    private string Action2ClipName(string action)
    {
        string result = "";
        if(m_RenderType == SlgBattleMgr.SoldierRenderType.Model)
        {
            switch (action)
            {
                case SlgFightDef.c_sAction_Idle:
                    result = SlgFightDef.c_sModelAction_Idle;
                    break;
                case SlgFightDef.c_sAction_A1:
                    result = SlgFightDef.c_sModelAction_A1;
                    break;
                case SlgFightDef.c_sAction_Dead:
                    result = SlgFightDef.c_sModelAction_Die;
                    break;
                case SlgFightDef.c_sAction_Move:
                    result = SlgFightDef.c_sModelAction_Run;
                    break;
                case SlgFightDef.c_sAction_Skill:
                    result = SlgFightDef.c_sModelAction_S1;
                    break;
                case SlgFightDef.c_sAction_A2:
                    result = SlgFightDef.c_sModelAction_A2;
                    break;
            }
        }
        else if(m_RenderType == SlgBattleMgr.SoldierRenderType.Spine)
        {
            switch (action)
            {
                case SlgFightDef.c_sAction_Idle:
                    result = HeroFightDef.c_sAction_FIdle;
                    break;
                case SlgFightDef.c_sAction_A1:
                    result = HeroFightDef.c_sAction_Attack;
                    break;
                case SlgFightDef.c_sAction_Dead:
                    result = HeroFightDef.c_sAction_Dead;
                    break;
                case SlgFightDef.c_sAction_Move:
                    result = HeroFightDef.c_sAction_Run;
                    break;
            }
        }
        return result;
    }
    public Vector3 GetForwards()
    {
        return (m_pVo.m_bleft ? new Vector3(0, 90, 0) : new Vector3(0, -90, 0));
    }

    public Vector3 GetBacks()
    {
        return (m_pVo.m_bleft ? new Vector3(0, -90, 0) : new Vector3(0, 90, 0));
    }

    public Vector3 GetForwardDir()
    {
        return (m_pVo.m_bleft ? new Vector3(1, 0, 0) : new Vector3(-1, 0, 0));
    }

    public Vector3 GetBackDir()
    {
        return (!m_pVo.m_bleft ? new Vector3(1, 0, 0) : new Vector3(-1, 0, 0));
    }

    private Vector3 GetScale(float scale)
    {
        return (m_pVo.m_bleft ? new Vector3(1, 1, 1) * scale : new Vector3(-1, 1, 1) * scale);
    }

    public void ChangeState(string state,params object[] args)
    {
        m_pStateMachine.ChangeState(state, args);
    }
    public override bool HandleMessage(MessageBody body)
    {
        return m_pStateMachine.OnHandleMessage(body);
    }


    public Transform m_pTag;
    Collider[] colliders = new Collider[30];
    private int colliderNum = 0;
    private float dis;
    public string myState;
    public bool SearchTarget()
    {
        m_pTag = null;
        dis = 0;
        //colliderNum = Physics.OverlapBoxNonAlloc(m_pGameObj.transform.position+new Vector3(m_pVo.m_bleft?10:-10,0,0), new Vector3(20, 1, 1), colliders, Quaternion.identity, 1 << (m_pVo.m_bleft ? SlgFightDef.c_iLay_RightTroop : SlgFightDef.c_iLay_LeftTroop));
        //colliderNum = Physics.OverlapSphereNonAlloc(m_pGameObj.transform.position, m_pVo.config.lookRange, colliders,1<<(m_pVo.m_bleft? SlgFightDef.c_iLay_RightTroop:SlgFightDef.c_iLay_LeftTroop));
        //Debug.LogFormat("start:  {0}   {1}", colliderNum, colliders.Length);
        for (int i = 0; i < colliderNum; i++)
        {
            if (dis < Vector3.Distance(colliders[i].transform.position, m_pGameObj.transform.position))
            {
                m_pTag = colliders[i].transform;
            }
            //Debug.LogFormat("{0}  {1}  {2}", m_pGameObj.name, colliders[i].transform.parent.gameObject.name, dis);
        }
        //if (colliderNum > 0)
        //{
        //    m_pTag = colliders[Random.Range(0, colliderNum)].transform;
        //}
        return (m_pTag != null);
    }

    public void FreshDir()
    {
        //m_pMoveComp.UniformMoveDir(2, Vector3.Normalize(m_pTag.position - m_pGameObj.transform.position));
    }

    public bool ReadyAttack()
    {
        if(Vector3.Distance(m_pTag.position,m_pGameObj.transform.position)<= m_pVo.config.attackRange)
        {
            return true;
        }
        return false;
    }

    public void ShadowActive(bool active)
    {
        if(m_pShadow != null)
        {
            m_pShadow.gameObject.SetActive(active);
        }
    }

    public SlgEntityTroop GetTroop()
    {
        SlgEntityTroop troop = (SlgEntityTroop)GetParent();
        return troop;
    }
}

public class SlgSoldierState
{
    public const string c_sSoldier_Global = "soldier_global";
    public const string c_sSoldier_Idle = "soldier_idle";
    public const string c_sSoldier_Move = "soldier_move";
    public const string c_sSoldier_Attack = "soldier_attack";
    public const string c_sSoldier_Dead = "soldier_dead";
    public const string c_sSolider_Action = "solider_action";
    public const string c_sSolider_Shoot = "solider_shoot";

    //public static SoliderStateGlobal s_pSoldier_Global = new SoliderStateGlobal();
    public static SoliderStateIdle s_pSoldier_Idle = new SoliderStateIdle();
    //public static SoliderStateAttack s_pSoldier_Attack = new SoliderStateAttack();
    public static SoliderStateMove s_pSoldier_Move = new SoliderStateMove();
    public static SoliderStateDead s_pSoldier_Dead = new SoliderStateDead();
    public static SoliderStateAction s_pSolider_Action = new SoliderStateAction();
    public static SoliderStateShoot s_pSolider_Shoot = new SoliderStateShoot();
}
